`timescale 1ns / 1ns
// Description: volume control
// Author: JerryTech
// License: GPLv3

//SEG decoder refers to:https://wiki.lckfb.com/zh-hans/fpga-ljpi/beginner/seg.html

module volume_control #(
    parameter SYS_FREQ = 'd3072000,
    parameter KEY_POLARITY = 0
)
(
    input   wire            sys_clk,
    input   wire            reset,

    input   wire            key_vol_up,     //active low
    input   wire            key_vol_down,   //5 stages,0 is mute

    input   wire [31: 0]    audio_data_in,
    output  reg  [31: 0]    audio_data_out,

    output  reg  [7 : 0]    seg_display   //Common anode seg display
);

localparam DEBOUNCE_TIME = 40;
wire volume_up_pressed;
wire volume_down_pressed;
reg [3:0] volume_level;

key_debounce #(
    .SYS_FREQ       ( SYS_FREQ      ),
    .KEY_POLARITY   ( KEY_POLARITY  ),
    .DEBOUNCE_TIME  ( DEBOUNCE_TIME )
) u_key_up
(
    .sys_clk            (sys_clk),
    .reset              (reset),

    .key_in             (key_vol_up),
    .key_debounce_out   (volume_up_pressed)
);

key_debounce #(
    .SYS_FREQ       ( SYS_FREQ      ),
    .KEY_POLARITY   ( KEY_POLARITY  ),
    .DEBOUNCE_TIME  ( DEBOUNCE_TIME )
) u_key_down
(
    .sys_clk            (sys_clk),
    .reset              (reset),

    .key_in             (key_vol_down),
    .key_debounce_out   (volume_down_pressed)
);

always@(posedge sys_clk) begin
    if(reset) begin
        volume_level <= 8;
    end
    else if(volume_down_pressed)begin
        volume_level <= volume_level == 0 ? 0 : volume_level - 1;
    end
    else if(volume_up_pressed)begin
        volume_level <= volume_level == 8 ? 8 : volume_level + 1;
    end
end

//Signed audio data caculate.Note audio data is signed.
always@(posedge sys_clk) begin
    if(reset) begin
        audio_data_out <= 0;
    end
    else begin
        case(volume_level)
            'd0: begin 
                audio_data_out[31:16] <= 0;
                audio_data_out[15: 0] <= 0;
            end
            'd1: begin 
                audio_data_out[31:16] <= {{3{audio_data_in[31]}},audio_data_in[31:19]}; //1 / 8 volume
                audio_data_out[15: 0] <= {{3{audio_data_in[15]}},audio_data_in[15: 3]};
            end
            'd2: begin 
                audio_data_out[31:16] <= {{2{audio_data_in[31]}},audio_data_in[31:18]};//2 / 8 volume
                audio_data_out[15: 0] <= {{2{audio_data_in[15]}},audio_data_in[15: 2]};
            end
            'd3: begin 
                audio_data_out[31:16] <= {{2{audio_data_in[31]}},audio_data_in[31:18]} + {{3{audio_data_in[31]}},audio_data_in[31:19]};//3 / 8 volume
                audio_data_out[15: 0] <= {{2{audio_data_in[15]}},audio_data_in[15: 2]} + {{3{audio_data_in[15]}},audio_data_in[15: 3]};
            end
            'd4: begin 
                audio_data_out[31:16] <= {{1{audio_data_in[31]}},audio_data_in[31:17]};//4 / 8 volume
                audio_data_out[15: 0] <= {{1{audio_data_in[15]}},audio_data_in[15: 1]};
            end
            'd5: begin 
                audio_data_out[31:16] <= {{1{audio_data_in[31]}},audio_data_in[31:17]} + {{3{audio_data_in[31]}},audio_data_in[31:19]};//5 / 8 volume
                audio_data_out[15: 0] <= {{1{audio_data_in[15]}},audio_data_in[15: 1]} + {{3{audio_data_in[15]}},audio_data_in[15: 3]};
            end
            'd6: begin 
                audio_data_out[31:16] <= {{1{audio_data_in[31]}},audio_data_in[31:17]} + {{2{audio_data_in[31]}},audio_data_in[31:18]};//6 / 8 volume
                audio_data_out[15: 0] <= {{1{audio_data_in[15]}},audio_data_in[15: 1]} + {{2{audio_data_in[15]}},audio_data_in[15: 2]};
            end
            'd7: begin 
                audio_data_out[31:16] <= {{1{audio_data_in[31]}},audio_data_in[31:17]} + {{2{audio_data_in[31]}},audio_data_in[31:18]} + {{3{audio_data_in[31]}},audio_data_in[31:19]};//7 / 8 volume
                audio_data_out[15: 0] <= {{1{audio_data_in[15]}},audio_data_in[15: 1]} + {{2{audio_data_in[15]}},audio_data_in[15: 2]} + {{3{audio_data_in[15]}},audio_data_in[15: 3]};
            end
            'd8: begin 
                audio_data_out[31:16] <= audio_data_in[31:16];
                audio_data_out[15: 0] <= audio_data_in[15: 0];
            end
            default: begin
                audio_data_out[31:16] <= 0;
                audio_data_out[15: 0] <= 0;
            end
        endcase
    end
end

//Seg display. Refers to : https://wiki.lckfb.com/zh-hans/fpga-ljpi/
always @(posedge sys_clk) begin
    if(reset)
        seg_display <= 8'hFF;                   //清理 零
    else begin
        case(volume_level)              // 根据number的值选择对应的7段显示编码
            4'd0: seg_display <= 8'hC0;    // 显示数字0
            4'd1: seg_display <= 8'hF9;    // 显示数字1
            4'd2: seg_display <= 8'hA4;    // 显示数字2
            4'd3: seg_display <= 8'hB0;    // 显示数字3
            4'd4: seg_display <= 8'h99;    // 显示数字4
            4'd5: seg_display <= 8'h92;    // 显示数字5
            4'd6: seg_display <= 8'h82;    // 显示数字6
            4'd7: seg_display <= 8'hF8;    // 显示数字7
            4'd8: seg_display <= 8'h80;    // 显示数字8
            4'd9: seg_display <= 8'h90;    // 显示数字9
            default: ;             // 默认情况下不进行任何操作
        endcase
    end
end

endmodule
